package it.low.game.client;

import it.low.game.client.gui.graphics.GraphicElement;
import it.low.game.client.gui.graphics.GraphicPlaceholder;
import it.low.game.client.gui.graphics.MapBackground;
import it.low.game.client.server.ClientServerInterface;
import it.low.game.client.util.ClientLogManager;
import it.low.game.core.action.Action;
import it.low.game.core.element.ActiveElement;
import it.low.game.core.element.State;
import it.low.game.core.location.MapPoint;
import it.low.game.core.message.PlayerEvent;
import it.low.util.Constant;

import java.awt.Point;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import javax.swing.ImageIcon;

public class GameSession {
	
	private boolean running = false;
	private  Point offsetLocation = null;
	
	private MapBackground mapBackground = null;	
	private GamePlayer gamePlayer = null;	
	private GraphicPlaceholder graphicPlaceholder = null;	
	private Map<Long,GraphicElement> graphicElements = null;
	
	private ClientServerInterface clientServerInterface = null;
	
	public GameSession(ClientServerInterface clientServerInterface){
		this.offsetLocation = new Point(0,0);
		this.clientServerInterface = clientServerInterface;		
	}	
	
	public int init(long clientId){
		ClientLogManager.logMsg("call GameSession.init()");
		int sessionInitStatus = Constant.GENERIC_OK;		
		if(this.clientServerInterface!=null){
			if(sessionInitStatus>Constant.GENERIC_ERROR) sessionInitStatus = this.loadMapFromServer();
			if(sessionInitStatus>Constant.GENERIC_ERROR) sessionInitStatus = this.loadPlayerFromServer(clientId);
			if(sessionInitStatus>Constant.GENERIC_ERROR) sessionInitStatus = this.loadBotsFromSever(clientId);
			graphicPlaceholder = new GraphicPlaceholder();
		}else{
			sessionInitStatus = Constant.GENERIC_ERROR;
		}
		return sessionInitStatus;
	}
		
	public void start(){
		ClientLogManager.logMsg("call GameSession.start()");
		if(this.mapBackground!=null && this.graphicElements!=null && !this.graphicElements.isEmpty()){
			running = true;
		}
	}
	
	public void pause(){
		ClientLogManager.logMsg("call GameSession.pause()");
		running = false;
	}
	
	public void stop(){
		ClientLogManager.logMsg("call GameSession.stop()");
		running = false;
		// Destroy this session !!!
		this.mapBackground = null;
		this.graphicElements=null;
	}
	
	public boolean isRunning(){
		return running;
	}
	
	public void loadGameMapBackground(MapBackground mapBackground){
		this.mapBackground = mapBackground;
	}
	
	public MapPoint getMapRelativePoint(Point gamePanelPoint){
		double mapPointX = gamePanelPoint.x - offsetLocation.x;
		double mapPointY = gamePanelPoint.y - offsetLocation.y;
		return new MapPoint(mapPointX,mapPointY);
	}
	
	public Point getGamePanelRelativePoint(MapPoint mapPoint){
		int gamePanelPointX = (int)mapPoint.x + offsetLocation.x;
		int gamePanelpointY = (int)mapPoint.y + offsetLocation.y;
		return new Point(gamePanelPointX,gamePanelpointY);
	}
	
	public void movePlayer(MapPoint mapPoint){		
		graphicPlaceholder.invalid();
		PlayerEvent playerEvent = new PlayerEvent(GameClient.CLIENT_ID, Action.TYPE.MOVE, mapPoint);
		clientServerInterface.sendPlayerEvent(playerEvent);
		graphicPlaceholder.update(Action.TYPE.MOVE, mapPoint);
	}
	
	public MapBackground getMapBackground(){
		return mapBackground;
	}
	
	public GamePlayer getPlayer(){
		return gamePlayer;
	}
	
	public GraphicPlaceholder getPlaceholder(){
		return graphicPlaceholder;
	}
	
	public Collection<GraphicElement> getGraphicElements(){
		if(graphicElements!=null)
			return graphicElements.values();
		else
			return null;
	}	
	
	public void setOffset(MapPoint mapPoint){
		double offsetX = GameClient.HALF_VIEW_WIDTH - mapPoint.getX();
		double offsetY = GameClient.HALF_VIEW_HEIGHT - mapPoint.getY();
		// CHECK IF OFFSET IS AT THE BORDER LINE
		if(offsetX > 0) offsetX = 0;
		if(offsetY > 0) offsetY = 0;
		if(offsetX < (GameClient.VIEW_WIDTH - mapBackground.width)) offsetX = GameClient.VIEW_WIDTH - mapBackground.width;
		if(offsetY < (GameClient.VIEW_HEIGHT - mapBackground.height)) offsetY = GameClient.VIEW_HEIGHT - mapBackground.height;
		offsetLocation.setLocation(offsetX, offsetY);
	}
	
	public Point getOffset(){
		return offsetLocation;
	}
	
	public void update(long elapsedTime){
		
		// REFRESH PLAYER
		State playerState = clientServerInterface.receivePlayerState(GameClient.CLIENT_ID).getState();
		gamePlayer.setMapPosition(playerState.getMapPosition());
		
		// REFRESH PLACEHOLDER
		if(graphicPlaceholder.isValid()){
			if(playerState.getMapPosition().isNear(graphicPlaceholder.getTarget().getMapPosition(),1)){
				graphicPlaceholder.invalid();
			}
		}
		
		// REFRESH ELEMENTS
		
//		Set<ActiveElement> activeElements = clientServer.getActiveElements(player.getPlayerId());
//		for(ActiveElement activeElement : activeElements){
//			long id = activeElement.getElementId();
//			MapActiveElement mapActiveElement = mapActiveElements.get(id);
//			MapPoint mp = activeElement.getMapPosition();
//			mapActiveElement.setMapPosition(mp);
//		}
		
	}
	
	// LOAD CLIENT MAP FROM THE SERVER MAP DESCRIPTION	
	private int loadMapFromServer(){
		ClientLogManager.logMsg("call GameSession.loadMapFromServer()");
		int mapInitStatus = Constant.GENERIC_OK;
		
		// GET THE MAP DESCRIPTION FROM THE SERVER
		String[][] mapDescription = clientServerInterface.loadMap();
		if(mapDescription!=null){
			int w = mapDescription.length;
			int h = mapDescription[0].length;
			
			// INIT THE BACKGROUND MAP TILES
			MapBackground mapBackground = new MapBackground(w,h);		
			for(int i=0 ; i<w ; i++){
				for(int j=0 ; j<h ; j++){
					// LOAD BACKGROUND IMAGES
					mapBackground.setBGMapTile(i, j, new ImageIcon(mapDescription[i][j]));
				}
			}
			// SET THE MAP BACKGROUND FOR THE CLIENT
			this.loadGameMapBackground(mapBackground);
		}else{
			mapInitStatus = Constant.GENERIC_ERROR;
		}
		return mapInitStatus;
	}
		
	
	// INIT CLIENT PLAYER FROM THE SERVER PLAYER DESCRIPTION
	private int loadPlayerFromServer(long clientId){
		ClientLogManager.logMsg("call GameSession.loadPlayerFromServer("+clientId+")");
		int playerInitStatus = Constant.GENERIC_OK;
		
		long playerId = clientId;
		// GET THE PLAYER DESCRIPTION FROM THE SERVER
		ActiveElement activeElementPlayer = clientServerInterface.loadPlayer(playerId);
		if(activeElementPlayer!=null){
			String imgPath = activeElementPlayer.getAttribute(ActiveElement.ELEM_IMAG);
			if(imgPath!=null){
				ImageIcon imageIcon = new ImageIcon(imgPath);
				if(!activeElementPlayer.isInit()){
					// CALCULATE SIZE FROM IMAGE
					int size = imageIcon.getIconWidth();
					// CALCULATE POSITION FROM MAP
					MapPoint mapPosition = new MapPoint(GameClient.HALF_VIEW_WIDTH,GameClient.HALF_VIEW_HEIGHT);
					activeElementPlayer = clientServerInterface.initPlayer(playerId, size, mapPosition);
				}
				graphicElements = new HashMap<Long,GraphicElement>();
				gamePlayer = new GamePlayer();
				gamePlayer.setState(activeElementPlayer.getElementState().getState());
				gamePlayer.initGraphic(imageIcon);
				graphicElements.put(activeElementPlayer.getElementId(), gamePlayer);
			}
		}else{
			playerInitStatus = Constant.GENERIC_ERROR;
		}
		return playerInitStatus;
	}
	
	// LOAD CLIENT BOTS FROM THE SERVER PLAYER DESCRIPTION
	private int loadBotsFromSever(long playerId){
		ClientLogManager.logMsg("call GameSession.initBotsFromSever("+playerId+")");
		int botsInitStatus = Constant.GENERIC_OK;
		
		// GET THE BOTS DESCRIPTION FROM THE SERVER
		Collection<ActiveElement> activeElementBots = clientServerInterface.loadBots();		
		if(activeElementBots!=null){
			for(ActiveElement activeElementBot : activeElementBots){
				String imgPath = activeElementBot.getAttribute(ActiveElement.ELEM_IMAG);
				if(imgPath!=null){
					ImageIcon imageIcon = new ImageIcon(imgPath);
					if(!activeElementBot.isInit()){
						// CALCULATE SIZE FROM IMAGE
						int size = imageIcon.getIconWidth();						
						activeElementBot = clientServerInterface.initBot(activeElementBot.getElementId(), size);
					}
					GraphicElement graphicElementBot = new GraphicElement();
					graphicElementBot.setState(activeElementBot.getElementState().getState());
					graphicElementBot.initGraphic(imageIcon);
					graphicElements.put(activeElementBot.getElementId(), graphicElementBot);
				}
			}
		}else{
			botsInitStatus = Constant.GENERIC_ERROR;
		}
		return botsInitStatus;
	}
	
}
